//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Expressions
{
    internal abstract class CellReference : Reference, IRangeReferenceItem
    {
#if DEBUG
        public override string ToString()
        {
            return base.ToString() + Label;
        }
#endif

        internal string NameOrlabel
        {
            get
            {
                var test = Enumerable.FirstOrDefault(this.Worksheet.Workbook.DefinedNames, dd => dd.Matches(Cell));
                if (test != null)
                    return test.Name;
                return Label;
            }
        }

        internal abstract RowReference Row { get; }
        internal abstract ColumnReference Column { get; }
        public abstract Cell Cell { get; }

        public CellAddress Address
        {
            get { return new CellAddress(Row.Anchor.Index, Column.Anchor.Index); }
        }

        #region IRangeReferenceItem Members

        public int MinRowIndex
        {
            get { return Cell.Row.Index; }
        }

        public int MaxRowIndex
        {
            get { return Cell.Row.Index; }
        }

        public int MinColumnIndex
        {
            get { return Cell.Column.Index; }
        }

        public int MaxColumnIndex
        {
            get { return Cell.Column.Index; }
        }

        [Obsolete]
        public string Label
        {
            get
            {
                if (Worksheet.Workbook.NamingConvention.RowBeforeColumn)
                    return Row.Label + Column.Label;
                return Column.Label + Row.Label;
            }
        }

        internal bool IsDeleted
        {
            get { return Column.IsDeleted || Row.IsDeleted; }
        }

        IRangeReferenceItem IRangeReferenceItem.Offset(CellRelativeAddress address)
        {
            return Offset(address);
        }

        #endregion

        public string GetText(TextContext context)
        {
            if (Worksheet.Workbook.NamingConvention.RowBeforeColumn)
                return Row.GetText(context) + Column.GetText(context);
            return Column.GetText(context) + Row.GetText(context);
        }

        public abstract CellReference Offset(CellRelativeAddress a);

        public Cell GetCell(EvaluationContext context)
        {
            Contract.Requires(context != null);
            Contract.Ensures(Contract.Result<Cell>() != null);
            return Worksheet[GetCellAddress(context)];
        }
        public CellAddress GetCellAddress (EvaluationContext context)
        {
            Contract.Requires(context != null);
            Row row = Row.GetRow(context);
            Column column = Column.GetColumn(context);
            return new CellAddress(row.Index, column.Index);
        }

        internal abstract CellReference ToggleLock();

        public CellReference Transposed(Cell target)
        {
            var cell = this.GetCell(new CellEvaluationContext(target));
            var oldOffset = cell.Address - target.Address;
            var newOffset = new CellRelativeAddress(oldOffset.Column, oldOffset.Row);
            return Offset(newOffset - oldOffset);
        }

        internal abstract CellReference Projected(Worksheet targetWorksheet);
    }
}